import csv
import random
import math


# 读取csv文件 转换数据类型
def load_csv(filename):
    lines = csv.reader(open(filename, "r"))
    datalist = list(lines)
    for i in range(len(datalist)):
        datalist[i] = [float(x) for x in datalist[i]]
    return datalist


# 该函数将数据集随机分割为训练集和剩余部分
def split_datalist(datalist, split_ratio):
    # 只要总数据的(split_ratio*100)%作为训练数据集
    train_size = int(len(datalist) * split_ratio)
    train_list = []
    copy_datalist = datalist
    # 取train_size个数据
    while len(train_list) < train_size:
        # 先随机生成一个范围在1到(copy_datalist的长度)的整数
        index = random.randrange(len(copy_datalist))
        # 从copy_datalist弹出并接到
        train_list.append(copy_datalist.pop(index))
    # 返回得到的训练数据列表 和 作为测试的数据列表
    return [train_list, copy_datalist]


# construct dictionary
def separate_by_class(datalist):  # 将数据集按照类别分开。
    separated = {}
    for i in range(len(datalist)):
        vector = datalist[i]
        if (vector[-1] not in separated): # 分成{0：[],1：[]}
            separated[vector[-1]] = []
        separated[vector[-1]].append(vector)
    # 返回了一个字典 字典中的values均为列表，一个列表存储的是没有糖尿病的数据，另一个存储的是患有糖尿病的数据
    return separated


def mean(numbers):  #
    return sum(numbers) / float(len(numbers))


def stdev(numbers):
    avg = mean(numbers)
    variance = sum([math.pow(x - avg, 2) for x in numbers]) / float(len(numbers))
    return math.sqrt(variance)


def prior_probability(datalist, len_train_set):  # 计算数据集的平均值和标准差，summarize_by_class函数对每个类别的数据进行汇总。
    return len(datalist) / len_train_set


# 给定数据集计算属性的平均值和标准差，并返回这些统计量以及类别的先验概率
def summarize(datalist, len_train_set):
    #zip() 函数用于将可迭代对象作为参数，将对象中对应的元素打包成一个个元组，然后返回由这些元组组成的对象
    #mean()求平均数 datalist[i]为包含各个属性的列表 len_train_set为总数据数量
    summaries = [(mean(attribute), stdev(attribute)) for attribute in zip(*datalist)]
    pb = prior_probability(datalist, len_train_set)
    del summaries[-1]
    summaries.append(pb)
    return summaries


def summarize_by_class(datalist):  # summarize函数计算数据集的平均值和标准差，summarize_by_class函数对每个类别的数据进行汇总
    separated = separate_by_class(datalist) # 得到一个字典 分为糖尿病和没有糖尿病
    summaries = {} # 定义一个字典
    for class_value, instances in separated.items():
        summaries[class_value] = summarize(instances, len(datalist))
    return summaries


def calculate_probability(x, mean, stdev):  # 计算给定数据点的概率密度函数值。
    exponent = math.exp(-(math.pow(x - mean, 2) / (2 * math.pow(stdev, 2))))
    return (1 / (math.sqrt(2 * math.pi) * stdev)) * exponent


def calculate_class_probabilities(summaries, input_vector):  # 计算输入向量属于每个类别的概率。
    probabilities = {}
    for class_value, class_summaries in summaries.items():
        probabilities[class_value] = 1
        for i in range(len(class_summaries) - 1):
            mean, stdev = class_summaries[i]
            x = input_vector[i]
            probabilities[class_value] *= calculate_probability(x, mean, stdev)
        probabilities[class_value] *= class_summaries[-1]
    return probabilities


def predict(summaries, input_vector):  # 根据计算出的概率预测输入向量的最佳类别。
    probabilities = calculate_class_probabilities(summaries, input_vector)
    best_label, best_prob = None, -1
    for class_value, probability in probabilities.items():
        if best_label is None or probability > best_prob:
            best_prob = probability
            best_label = class_value
    return best_label


def get_predictions(summaries, test_set):  # 预测结果获取：get_predictions函数对测试集进行预测。

    predictions = []
    for i in range(len(test_set)):
        result = predict(summaries, test_set[i])
        predictions.append(result)
    return predictions


def get_accuracy(test_set, predictions):  # 计算预测的准确率
    correct = 0
    for i in range(len(test_set)):
        if (test_set[i][-1] == predictions[i]):
            correct += 1
    return (correct / float(len(test_set))) * 100.0


def main():
    # filename = "nb_data.csv"
    split_ratio = 0.67
    # datalist= load_csv('./nb_data.csv')
    # 打开准备的数据 并保存到datalist
    datalist = load_csv('D:\\PY Project\\machine-learning\\pima-indians-diabetes.csv')
    # 将数据分割开两份
    train_set, test_set = split_datalist(datalist, split_ratio)
    print('Split {0} rows into train = {1} and test = {2} rows'.format(len(datalist), len(train_set), len(test_set)))
    # prepare model
    summaries = summarize_by_class(train_set)
    # test model
    # predictions = get_predictions(summaries, test_set)
    # accuracy = get_accuracy(test_set, predictions)
    # print('准确度：{0}%'.format(accuracy))
    # print('患病情况{0}'.format(predictions))


if __name__ == '__main__':
    main()
